﻿using System;

namespace Yappi.Common
{
    public class Singleton<TInstanceType> where TInstanceType:class 
    {
        private readonly Object _syncRoot = new object();
        private volatile TInstanceType _instance;
        private Func<TInstanceType> _construction;
        
        public Singleton(Func<TInstanceType> construction)
        {
            if(construction == null)
            {
                throw new ArgumentException("Null delegate is not allowed.");
            }
            _construction = construction;
        }

        public TInstanceType Instance
        {
            get
            {
                if(ReferenceEquals(_instance,null))
                {
                    lock (_syncRoot)
                    {
                        if (ReferenceEquals(_instance,null))
                        {
                            _instance = _construction();
                            _construction = null;
                            if (ReferenceEquals(_instance, null))
                            {
                                throw new InvalidOperationException("Constructing delegate returned null reference.");
                            }
                        }
                    }
                }
                return _instance;
            }
        }

        public static implicit operator TInstanceType(Singleton<TInstanceType> singleton)
        {
            return singleton.Instance;
        }
    }
}
